package cn.gudian.cms.utils;

import magick.*;

import java.awt.*;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by IntelliJ IDEA.
 * User: Administrator
 * Date: 2010-4-16
 * Time: 18:24:45
 * To change this template use File | Settings | File Templates.
 */
public class ImageUtil {
    static {
        //不能漏掉这个，不然jmagick.jar的路径找不到
        System.setProperty("jmagick.systemclassloader", "no");
    }

    private static String[] IMG_FILE_TYPE = {"jpg", "gif", "png", "jpeg"};// 文件类型是图片

    public static final String KEY_NAME = "name";
    public static final String KEY_SIZE = "size";
    public static final String KEY_PATH = "path";

    //水印的位置
    public static final String CENTER = "center";
    public static final String LEFT_UP = "leftUp";
    public static final String LEFT_DOWN = "leftDown";
    public static final String RIGHT_UP = "rightUp";
    public static final String RIGHT_DOWN = "rightDown";
    public static final String ALL = "all";//水印布满整个原图
    public static final String LEFT_UP_ABS = "leftUpAbs";//绝对左上,带ABS的为绝对顶到原图的某个角
    public static final String LEFT_DOWN_ABS = "leftDownAbs";
    public static final String RIGHT_UP_ABS = "rightUpAbs";
    public static final String RIGHT_DOWN_ABS = "rightDownAbs";


    //得到ImageInfo对象

    private static java.io.File getFile(String fileRealPath) throws UploadException {
        String extension = fileRealPath.substring(fileRealPath.lastIndexOf(".") + 1).toLowerCase();
        if (!isImg(extension))
            throw new UploadException("ERROR 4002:" + fileRealPath + " is not image file error");
        // 创建原图文件
        java.io.File originalFile = new java.io.File(fileRealPath);
        if (!originalFile.isFile()) {
            throw new UploadException("ERROR 4004:" + originalFile + " is not file error");
        }
        return originalFile;
    }

    // 把大图按比例缩小为小图，返回一个Map，包含生成文件的name、size、path三个信息

    public static Map scaleImg(String fileRealPath, double scale, double rotate, String prefix, int quality, boolean delOriginalImg)
            throws UploadException {
        return scaleImg(fileRealPath, scale, rotate, prefix, quality, delOriginalImg, null, null, false, false);
    }

    public static Map scaleImg(String fileRealPath, double scale, double rotate, String prefix, int quality, boolean delOriginalImg,
                               String markPath, String withMarkPosition, boolean isOriginalMark, boolean isToImgMark)
            throws UploadException {
        Map fileMap = new HashMap();
        if (scale <= 0 || quality <= 0)
            throw new UploadException("ERROR 5003:scale and quality can't <=0");
        MagickImage image = null;
        MagickImage toImg = null;
        try {
            // 定义原图
            java.io.File originalFile = getFile(fileRealPath);
            ImageInfo info = new ImageInfo(originalFile.getAbsolutePath());
            image = new MagickImage(info);
            /*if(scale == 1 && rotate == 0){
                fileMap.put(KEY_NAME, originalFile.getName());
                fileMap.put(KEY_PATH, fileRealPath);
                fileMap.put(KEY_SIZE, image.sizeBlob());
                return fileMap;
            }*/
            info.setQuality(quality);
            Dimension imageDim = image.getDimension();
            // 得到缩放图
            java.io.File toFile = new java.io.File(originalFile.getParentFile().getAbsolutePath(), prefix + originalFile.getName());
            toImg = image.scaleImage((int) (imageDim.width * scale), (int) (imageDim.height * scale));
            if (rotate != 0)
                toImg = toImg.rotateImage(rotate);
            //加水印
            if (isToImgMark && markPath != null && withMarkPosition != null) {
                waterMark(toImg, markPath, withMarkPosition);
            }
            if (isOriginalMark && !delOriginalImg && markPath != null && withMarkPosition != null) {
                image = waterMark(image, markPath, withMarkPosition);
                image.writeImage(info);
            }
            toImg.setFileName(toFile.getAbsolutePath());
            toImg.writeImage(info);
            if (delOriginalImg)
                originalFile.delete();
            fileMap.put(KEY_NAME, toFile.getName());
            fileMap.put(KEY_PATH, toFile.getAbsolutePath());
            fileMap.put(KEY_SIZE, toImg.sizeBlob());
            return fileMap;
        }
        catch (Exception e) {
            throw new UploadException("ERROR 5008:deal image error " + e.getMessage());
        }
        finally {
            if (toImg != null) {
                toImg.destroyImages();
            }
            if (image != null) {
                image.destroyImages();
            }
        }
    }

    // 把大图按指定的大小缩成不变形的小图，不足的尺寸填充白色，返回一个Map，包含生成文件的name、size、path三个信息

    public static Map scaleImg(String fileRealPath, int toWidth,
                               int toHeight, int rotate, String prefix, int quality, boolean delOriginalImg)
            throws UploadException {
        return scaleImg(fileRealPath, toWidth, toHeight, rotate, prefix, quality, delOriginalImg, null, null, false, false);
    }

    public static Map scaleImg(String fileRealPath, int toWidth,
                               int toHeight, int rotate, String prefix, int quality, boolean delOriginalImg,
                               String markPath, String withMarkPosition, boolean isOriginalMark, boolean isToImgMark)
            throws UploadException {
        Map fileMap = new HashMap();
        if (toWidth <= 0 || toHeight <= 0 || quality <= 0)
            throw new UploadException("ERROR 5003:toWidth and toHeight and quality can't <=0");
        MagickImage image = null;
        MagickImage toImg = null;
        try {
            // 定义原图
            java.io.File originalFile = getFile(fileRealPath);
            ImageInfo info = new ImageInfo(originalFile.getAbsolutePath());
            image = new MagickImage(info);
            info.setQuality(quality);
            Dimension imageDim = image.getDimension();
            // 得到缩放图
            java.io.File toFile = new java.io.File(originalFile.getParentFile().getAbsolutePath(), prefix + originalFile.getName());
               if (rotate != 0)
                image = image.rotateImage(rotate);
            float oldRatio = (float) imageDim.width / imageDim.height;// 原文件的宽高比例
            float newRatio = (float) toWidth / toHeight;// 新文件的宽高比例
            if (oldRatio < newRatio) {
                toImg = image.scaleImage((int) Math.round(Arith.mul(Arith.div(toHeight, imageDim.height), imageDim.width)), toHeight);
            } else {
                toImg = image.scaleImage(toWidth, (int) Math.round(Arith.mul(Arith.div(toWidth, imageDim.width), imageDim.height)));
            }
            //加水印
            if (isToImgMark && markPath != null && withMarkPosition != null) {
                waterMark(toImg, markPath, withMarkPosition);
            }
            Dimension toImageDim = toImg.getDimension();
            //如果缩小后的图和指定生成的宽、高有不同，填充白色在空余部分
            if (toImageDim.width != toWidth || toImageDim.height != toHeight) {
                //按toWidth、toHeight的大小创建一个空白的底图，再将实际缩小的图放在空白图的上方
                //实际裁切的图在空白底图上的坐标位置
                int newX = 0;
                int newY = 0;
                if (oldRatio < newRatio) {
                    newX = (int) Math.round(Arith.div(Arith.sub(toWidth, toImageDim.width), 2));
                } else {
                    newY = (int) Math.round(Arith.div(Arith.sub(toHeight, toImageDim.height), 2));
                }
                MagickImage blankImage = fillImg(toImg, toFile.getAbsolutePath(), toWidth, toHeight, newX, newY, quality);
                fileMap.put(KEY_SIZE, blankImage.sizeBlob());
            } else {
                toImg.setFileName(toFile.getAbsolutePath());
                toImg.writeImage(info);
                fileMap.put(KEY_SIZE, toImg.sizeBlob());
            }
          //给原图加水印
            if (isOriginalMark && !delOriginalImg && markPath != null && withMarkPosition != null) {
                image = waterMark(image, markPath, withMarkPosition);
                image.writeImage(info);
            }
          
            if (delOriginalImg)
                originalFile.delete();
            fileMap.put(KEY_NAME, toFile.getName());
            fileMap.put(KEY_PATH, toFile.getAbsolutePath());
            return fileMap;
        }
        catch (Exception e) {
            throw new UploadException("ERROR 5008:deal image error " + e.getMessage());
        }
        finally {
            if (toImg != null) {
                toImg.destroyImages();
            }
            if (image != null) {
                image.destroyImages();
            }
        }
    }

    // 切割图片,参数为：文件路径、切割范围的x、y、宽、高、切割后新文件名的前缀、质量，是否删除原图，返回一个Map，包含生成文件的name、size、path三个信息

    public static Map cropImg(String fileRealPath, int x, int y, int toWidth,
                              int toHeight, String prefix, int quality, boolean delOriginalImg) throws UploadException {
        return cropImg(fileRealPath, x, y, toWidth,
                toHeight, prefix, quality, delOriginalImg,
                null, null, false, false);
    }

    public static Map cropImg(String fileRealPath, int x, int y, int toWidth,
                              int toHeight, String prefix, int quality, boolean delOriginalImg,
                              String markPath, String withMarkPosition, boolean isOriginalMark, boolean isToImgMark) throws UploadException {
        Map fileMap = new HashMap();
        MagickImage image = null;
        MagickImage toImg = null;
        if ((toWidth <= 0 && toHeight <= 0) || quality <= 0)
            throw new UploadException("ERROR 5003:toWidth and toHeight and quality can't <=0");
        try {
            // 定义原图
            java.io.File originalFile = getFile(fileRealPath);
            ImageInfo info = new ImageInfo(originalFile.getAbsolutePath());
            info.setQuality(quality);
            image = new MagickImage(info);
            Dimension imageDim = image.getDimension();
            // 得到裁切图
            java.io.File toFile = new java.io.File(originalFile.getParentFile().getAbsolutePath(), prefix + originalFile.getName());
            //如果toWidth或toHeight为0的话，表示不限制该边，如toHeight为0即不限制高度,此时，为了不填充多余的白底，将对于把x或Y设为0
            if (toWidth <= 0) {
                toWidth = imageDim.width;
                x = 0;
            }
            if (toHeight <= 0) {
                toHeight = imageDim.height;
                y = 0;
            }
            Rectangle rect = new Rectangle(x, y, toWidth, toHeight);
            toImg = image.cropImage(rect);
            Dimension toImageDim = toImg.getDimension();
            //加水印
            if (isToImgMark && markPath != null && withMarkPosition != null) {
                waterMark(toImg, markPath, withMarkPosition);
            }
            //如果期望裁切的部分不同于实际裁切的部分（比如x,y 是负数时等等）
            if (toImageDim.width != toWidth || toImageDim.height != toHeight) {
                //按toWidth、toHeight的大小创建一个空白的底图，再将实际裁切的图放在空白图的上方
                //实际裁切的图在空白底图上的坐标位置
                int newX = 0;
                int newY = 0;
                //以原图左上角为坐标原点时，裁切的矩形顶点坐标位于原图坐标系的第1区间
                if (x >= 0 && y < 0) {
                    newX = 0;
                    newY = -y;
                }//以原图左上角为坐标原点时，裁切的矩形顶点坐标位于原图坐标系的第2区间
                else if (x < 0 && y < 0) {
                    newX = -x;
                    newY = -y;
                }//以原图左上角为坐标原点时，裁切的矩形顶点坐标位于原图坐标系的第3区间
                else if (x < 0 && y >= 0) {
                    newX = -x;
                    newY = 0;
                }//以原图左上角为坐标原点时，裁切的矩形顶点坐标位于原图坐标系的第4区间
                else {// if(x >= 0 && y >= 0){
                    newX = 0;
                    newY = 0;
                }
                MagickImage blankImage = fillImg(toImg, toFile.getAbsolutePath(), toWidth, toHeight, newX, newY, quality);
                fileMap.put(KEY_SIZE, blankImage.sizeBlob());
            } else {
                toImg.setFileName(toFile.getAbsolutePath());
                toImg.writeImage(info);
                fileMap.put(KEY_SIZE, toImg.sizeBlob());
            }
            //给原图加水印
            if (isOriginalMark && !delOriginalImg && markPath != null && withMarkPosition != null) {
                image = waterMark(image, markPath, withMarkPosition);
                image.writeImage(info);
            }
            if (delOriginalImg)
                originalFile.delete();
            fileMap.put(KEY_NAME, toFile.getName());
            fileMap.put(KEY_PATH, toFile.getAbsolutePath());
            return fileMap;
        }
        catch (Exception e) {
            throw new UploadException("ERROR 5008:deal image error " + e.getMessage());
        }
        finally {
            if (toImg != null) {
                toImg.destroyImages();
            }
            if (image != null) {
                image.destroyImages();
            }
        }
    }

    //按toWidth、toHeight的大小创建一个空白的底图，再将传递进来的图放在该图的上方

    private static MagickImage fillImg(MagickImage toImg, String realPath, int toWidth, int toHeight, int newX, int newY, int quality) throws UploadException {
        MagickImage blankImage = null;
        try {
            blankImage = new MagickImage();
            byte[] pixels = new byte[toWidth * toHeight * 4];
            for (int i = 0; i < toWidth * toHeight; i++) {
                pixels[4 * i] = (byte) 255;
                pixels[4 * i + 1] = (byte) 255;
                pixels[4 * i + 2] = (byte) 255;
                pixels[4 * i + 3] = (byte) 0;
            }
            blankImage.constituteImage(toWidth, toHeight, "RGBA", pixels);
            ImageInfo blankInfo = new ImageInfo();
            blankInfo.setQuality(quality);
            DrawInfo drawInfo = new DrawInfo(blankInfo);
            drawInfo.setPrimitive("Rectangle 0 0 " + toWidth + " " + toHeight);
            drawInfo.setFill(PixelPacket.queryColorDatabase("#ffffff"));
            //drawInfo.setFill(new PixelPacket(231,231,231,90));
            blankImage.drawImage(drawInfo);
            //传递的图在空白底图上的坐标位置
            blankImage.compositeImage(CompositeOperator.AtopCompositeOp, toImg, newX, newY);
            blankImage.setFileName(realPath);
            blankImage.writeImage(blankInfo);
        }
        catch (Exception e) {
            throw new UploadException("ERROR 5008:deal image error " + e.getMessage());
        }
        return blankImage;
    }

    public static void waterMark(String imgRealPath, String markRealPath, String withMarkPosition) throws UploadException {
        // 定义原图
        MagickImage image = null;
        try {
            java.io.File originalFile = getFile(imgRealPath);
            ImageInfo info = new ImageInfo(originalFile.getAbsolutePath());
            info.setQuality(100);
            image = new MagickImage(info);
            waterMark(image, markRealPath, withMarkPosition);
            image.writeImage(info);
        } catch (Exception e) {
            throw new UploadException("ERROR 5008:deal image error " + e.getMessage());
        }
        finally {
            if (image != null) {
                image.destroyImages();
            }
        }
    }

    private static MagickImage waterMark(MagickImage img, String markRealPath, String withMarkPosition) throws UploadException {
        MagickImage markImage = null;
        MagickImage markImageTo = null;
        try {
            // 定义水印图
            java.io.File markFile = getFile(markRealPath);
            ImageInfo markInfo = new ImageInfo(markFile.getAbsolutePath());
            markImage = new MagickImage(markInfo);
            markInfo.setQuality(99);
            Dimension markDim = markImage.getDimension();
            //原图
            Dimension imgDim = img.getDimension();

            //如果水印的长或高大于原图，缩小水印
            int watermarkWidth = markDim.width;
            int watermarkHeight = markDim.height;
            double markRatio = (double) watermarkWidth / watermarkHeight;
            boolean isMarkScale = false;
            if (watermarkWidth > imgDim.width) {
                watermarkWidth = (int) (imgDim.width);
                watermarkHeight = (int) (watermarkWidth / markRatio);
                isMarkScale = true;
            }
            if (watermarkHeight > imgDim.height) {
                watermarkHeight = (int) (imgDim.height);
                watermarkWidth = (int) (watermarkHeight * markRatio);
                isMarkScale = true;
            }
            if (isMarkScale)
                markImageTo = markImage.scaleImage(watermarkWidth, watermarkHeight);


            int horizSpace = (int) (imgDim.width - watermarkWidth) / 10;
            int verticalSpace = (int) (imgDim.height - watermarkHeight) / 10;

            int markX = 0;
            int markY = 0;

            if (withMarkPosition.equals(CENTER)) {
                markX = (int) (imgDim.width / 2 - watermarkWidth / 2);
                markY = (int) (imgDim.height / 2 - watermarkHeight / 2);
            } else if (withMarkPosition.equals(LEFT_UP)) {
                markX = horizSpace;
                markY = verticalSpace;
            } else if (withMarkPosition.equals(LEFT_DOWN)) {
                markX = horizSpace;
                markY = (int) (imgDim.height - watermarkHeight - verticalSpace);
            } else if (withMarkPosition.equals(RIGHT_UP)) {
                markX = (int) (imgDim.width - watermarkWidth - horizSpace);
                markY = verticalSpace;
            } else if (withMarkPosition.equals(RIGHT_DOWN)) {
                markX = (int) (imgDim.width - watermarkWidth - horizSpace);
                markY = (int) (imgDim.height - watermarkHeight - verticalSpace);
            } else if (withMarkPosition.equals(LEFT_UP_ABS)) {
                markX = 0;
                markX = 0;
            } else if (withMarkPosition.equals(LEFT_DOWN_ABS)) {
                markX = 0;
                markY = (int) (imgDim.height - watermarkHeight);
            } else if (withMarkPosition.equals(RIGHT_UP_ABS)) {
                markX = (int) (imgDim.width - watermarkWidth);
                markY = 0;
            } else if (withMarkPosition.equals(RIGHT_DOWN_ABS)) {
                markX = (int) (imgDim.width - watermarkWidth);
                markY = (int) (imgDim.height - watermarkHeight);
            }
            img.compositeImage(CompositeOperator.AtopCompositeOp, markImageTo == null ? markImage : markImageTo,
                    markX, markY);
            return img;
        } catch (Exception e) {
            throw new UploadException("ERROR 5008:deal image error " + e.getMessage());
        } finally {
            if (markImage != null) {
                markImage.destroyImages();
            }
            if (markImageTo != null) {
                markImageTo.destroyImages();
            }
        }
    }

    // 检查文件的后缀名是不是规定的后缀名

    public static void checkFileExt(String fileExtName, String[] fileTypes)
            throws UploadException {
        if (fileExtName == null)
            throw new UploadException("ERROR 4001:can't upload blank extension");

        if (fileTypes.length > 0) {// 如果为空为所有类型都可以
            boolean typeOk = false;
            StringBuffer typeName = new StringBuffer();
            for (int x = 0; x < fileTypes.length; x++) {
                if (x != 0)
                    typeName.append(",");
                typeName.append(fileTypes[x]);
                if (fileExtName.equalsIgnoreCase(fileTypes[x])) {
                    typeOk = true;
                    break;
                }
            }
            if (!typeOk)
                throw new UploadException("ERROR 4001:please upload extension at " + typeName + "");
        }
    }

    // 判断某个后缀名是不是图片文件

    public static boolean isImg(String fileExtName) throws UploadException {
        for (int i = 0; i < IMG_FILE_TYPE.length; i++) {
            if (fileExtName.equalsIgnoreCase(IMG_FILE_TYPE[i]))
                return true;
        }
        return false;
    }

    //互联网路径(必须以http://开头)转换为本地磁盘路径,需传递盘符，如z://，该方法就将域名转换为盘符

    public static String urlToRealPath(String url, String realRoot) {
        return realRoot + url.substring(url.indexOf("/", 9) + 1);
    }
    //本地磁盘路径转换为互联网路径,需传递域名
    //换到linux上后该方法需要改动

    public static String realPathToUrl(String realPath, String rootPath, String domain) {
        realPath = realPath.replaceAll("\\\\", "/");
        String cutStr = null;
        if (rootPath.charAt(3) == '/')
            cutStr = realPath.substring(rootPath.length() - 2);
        else
            cutStr = realPath.substring(rootPath.length() - 1);
        if (domain.endsWith("/"))
            domain = domain.substring(0, domain.length() - 1);
        if (domain.startsWith("http"))
            return domain + cutStr;
        else if (domain == "")
            return cutStr;
        else
            return "http://" + domain + cutStr;
    }

    public static void main(String args[]) {
        try {
            //scaleImg("e://test/a.jpg", 0.1, 0, "s_", 100, false, "e://test/A02.png", CENTER, false);
            //scaleImg("e://test/a2.jpg", 500,
            //                      500, "a_", 100, false,
            //                      "e://test/A02.png", RIGHT_DOWN, true);
            //cropImg("e://test/a2.jpg", 100, 100, 500,
            //                       500, "b_", 100, true,
            //                       "e://test/A02.png", LEFT_DOWN, true, true);
//            waterMark("e://test/aaa1.jpg", "e://test/anjuwarter2.png", RIGHT_DOWN);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
